/**
 * @(#)YcsCaptchaCodeUtils.java, 2021/12/21.
 * <p/>
 * Copyright 2021 Netease, Inc. All rights reserved.
 * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package site.ycsyxt.common.util;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Random;

import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
import com.google.code.kaptcha.util.Config;

import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER;
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_HEIGHT;
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_WIDTH;
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_IMPL;
import static com.google.code.kaptcha.Constants.KAPTCHA_OBSCURIFICATOR_IMPL;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_CONFIG_KEY;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE;
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_IMPL;

/**
 * 验证码操作相关工具类
 *
 * @author ycs(15241496739 @ 163.com)
 * @date 2021/12/26
 **/
public class CaptchaCodeUtils extends DefaultTextCreator {
    /**
     * 数学验证码计算式数据来源
     */
    private static final String[] NUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");

    /**
     * 数学验证码计算式对应索引
     */
    public static final String MATH_KEY = "key";

    /**
     * 数据验证码计算式结果对应索引
     */
    public static final String MATH_VAL = "val";

    public static final String SPLIT = "@";

    public static final String EXTENSION = "jpg";

    private static final Producer charProducer = CaptchaConfig.getCharProducer();

    private static final Producer mathProducer = CaptchaConfig.getMathProducer();

    /**
     * 获取字符验证码文本
     *
     * @return
     */
    public static String createCharText() {
        return charProducer.createText();
    }

    /**
     * 获取字符验证码图片
     *
     * @param charText 字符验证码文本
     * @return
     */
    public static BufferedImage createCharImage(String charText) {
        return charProducer.createImage(charText);
    }

    /**
     * 获取数学验证码计算式和计算结果
     * <p>
     * 计算式 = result.get(YcsCaptchaCodeUtils.MATH_KEY)
     * <p>
     * 计算值 = result.get(YcsCaptchaCodeUtils.MATH_VAL)
     *
     * @return result
     */
    public static Map<String, String> createMathText() {
        String text = mathProducer.createText();
        String key = text.substring(0, text.lastIndexOf(SPLIT));
        String val = text.substring(text.lastIndexOf(SPLIT) + 1);

        Map<String, String> result = new HashMap<>();
        result.put(MATH_KEY, key);
        result.put(MATH_VAL, val);
        return result;
    }

    /**
     * 获取数学验证码图片
     *
     * @param mathText     数学验证码计算式
     * @param outputStream 图片输出流
     * @return
     */
    public static void createMathImage(String mathText, OutputStream outputStream) {
        BufferedImage mathImage = mathProducer.createImage(mathText);
        try {
            ImageIO.write(mathImage, EXTENSION, outputStream);
        } catch (IOException e) {
            throw new RuntimeException("获取数学验证码图片失败！\n" + e);
        }
    }

    @Override
    public String getText() {
        int result = 0;
        Random random = new Random();
        int x = random.nextInt(10);
        int y = random.nextInt(10);
        StringBuilder suChinese = new StringBuilder();
        int randomOperands = (int) Math.round(Math.random() * 2);
        if (randomOperands == 0) {
            result = x * y;
            suChinese.append(NUMBERS[x]);
            suChinese.append(" * ");
            suChinese.append(NUMBERS[y]);
        } else if (randomOperands == 1) {
            if (!(x == 0) && y % x == 0) {
                result = y / x;
                suChinese.append(NUMBERS[y]);
                suChinese.append(" / ");
                suChinese.append(NUMBERS[x]);
            } else {
                result = x + y;
                suChinese.append(NUMBERS[x]);
                suChinese.append(" + ");
                suChinese.append(NUMBERS[y]);
            }
        } else if (randomOperands == 2) {
            if (x >= y) {
                result = x - y;
                suChinese.append(NUMBERS[x]);
                suChinese.append(" - ");
                suChinese.append(NUMBERS[y]);
            } else {
                result = y - x;
                suChinese.append(NUMBERS[y]);
                suChinese.append(" - ");
                suChinese.append(NUMBERS[x]);
            }
        } else {
            result = x + y;
            suChinese.append(NUMBERS[x]);
            suChinese.append(" + ");
            suChinese.append(NUMBERS[y]);
        }
        suChinese.append(" = ?").append(SPLIT).append(result);
        return suChinese.toString();
    }
}

class CaptchaConfig {
    /**
     * 字符验证码
     *
     * @return
     */
    static DefaultKaptcha getCharProducer() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为yes-有
        properties.setProperty(KAPTCHA_BORDER, "no");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }

    /**
     * 数学表达式验证码，使用 @ 分隔计算式和结果， 如 1 + 2 = @3
     *
     * @return
     */
    static DefaultKaptcha getMathProducer() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为yes-有
        properties.setProperty(KAPTCHA_BORDER, "no");
        // 边框颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        // 验证码文本生成器
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ycsyxt.YcsCaptchaCodeUtils");
        // 验证码文本字符间距 默认为2
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 验证码噪点颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        // 干扰实现类
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
